package org.deng.learn.concurrent.pc;

import java.util.LinkedList;

/**
 * @author 邓力宾
 * @date 2020/5/15 下午4:27
 * @desc 使用wiat和notify实现生产者消费者模式
 */
public class WaitNotifyProducerConsumerDemo<T> {
    //容器
    final  private LinkedList<T> list = new LinkedList<>();
    final private int max = 3; //最大存放元素个数
    private  int count = 0; //当前元素个数



    //生产 用的this锁
    public synchronized void put(T t){
        while (count == max){ // 使用while，而不是if（
            // 如果用if，只有一个生产者不会有差别，但如果是多个生产者
            // 比如：有两个生成者，假设此时容器是3个元素已经满了，2个生产者线程都等着，此时消费者线程消费了一个元素，
            // 然后把两个生产者线程唤醒，两个生产者线程就不会再次判断容器是否已满，就都会生产元素导致生产的元素大于容器容量）
            try {
                System.out.println(t+"满了");
                this.wait(); //容器满了 等着 释放锁 (进入等待池)
                System.out.println("继续生产"+t);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        list.add(t);
        count++;
        System.out.println("生产了一个元素"+t);
        this.notifyAll(); //有元素了 通知消费者取元素
    }

    //消费 用的this锁
    public synchronized T get() throws InterruptedException {
        T t = null;
        while (count == 0){ //用while 而不是if
            System.out.println("空了");
            this.wait();//没元素 等着 释放锁
            System.out.println("继续消费");
        }

        t = list.removeFirst();
        count --;
        System.out.println("消费了一个元素"+t);
        this.notifyAll(); //通知生产者可以生产了 不会释放锁
        return t;

    }

    public  static void main(String[] args){
        WaitNotifyProducerConsumerDemo<String> producerConsumer = new WaitNotifyProducerConsumerDemo<>();
        //开始生产
        new Thread(()->{
            producerConsumer.put("a");
            producerConsumer.put("b");
            producerConsumer.put("c");
            producerConsumer.put("d");
            producerConsumer.put("e");
            producerConsumer.put("f");
        }).start();


        //开始消费
        new Thread(()->{
            try {
                producerConsumer.get();
                producerConsumer.get();
                producerConsumer.get();
                producerConsumer.get();
                producerConsumer.get();
                producerConsumer.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }).start();
    }
}
